//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <malloc.h>
#include <pseudo.h>
#include "_sprintf.h"

#ifndef _mips

void AnsiToUnic(wchar_t *pwszName, const char *pszName);

// bugbug: this function is added for intel optimizing
//              Please delete this when intel fix up their compiler's bug
EXTERN_C int CDECL putchar(int c)
{
    //wchar_t wstr[2] = {(wchar_t)c, 0};

    //CPseudoSyscall::SysPrint(wstr);
    return c;
}

EXTERN_C int CDECL vprintf(const char *fmt, va_list ap)
{
    char szBuf[256];

    int nLength = vsprintf(szBuf, fmt, ap);

    wchar_t *wsz = (wchar_t*)_alloca((strlen(szBuf) + 1) * sizeof(wchar_t));
    AnsiToUnic(wsz, szBuf);
    //CPseudoSyscall::SysPrint(wsz);

    return nLength;
}

EXTERN_C int CDECL printf(const char *fmt,...)
{
    va_list ap;

    va_start(ap, fmt);

    int nLength = vprintf(fmt, ap);

    va_end(ap);

    return nLength;
}

EXTERN_C int CDECL wprintf(const wchar_t *fmt,...)
{
    return 0;
}

//EXTERN_C int CDECL sprintf(char *, const char *, ...)
//{
//    return 0;
//}

#else

static int __cdecl comPrintf(const char c)
{
    ASM(
        "move   a0, %0;"
        "li     v0, 34;"
        "syscall;", c);

    return 0;
}

/*convert  figure to 32 bits Hex string*/
static char * ToHexStr(int c)
{
    int v, i, j;
    static char gpHex[9];

    memset(gpHex, 0, 9 * sizeof(char));
    for (i = 0, j = 7; i < 8; i++) {
        v = c & 0x000f;

        if (v < 0xa) {
            gpHex[j] = v + 0x30;
        }
        else {
            gpHex[j] = v + 0x57;
        }

        j--;
        c >>= 4;
    }

    return gpHex;
}

/*convert  figure to 32 bits Dec string*/
static char * ToDecStr(int k)
{
    static char gpDec[12];
    char temp[12];
    int i = 0;
    int j = 0;

    memset(gpDec, 0, 12 * sizeof(char));
    memset(temp, 0, 12 * sizeof(char));

    if (k < 0) {
        k = -k;
        gpDec[0] = '-';
        j = 1;
    }

    do {
        temp[i] = k % 10;
        k = k / 10;
        i++;
    } while (k);

    i--;
    for (; i >= 0; j++, i--)
        gpDec[j] = temp[i] + 0x30;

    gpDec[++j] = '\0';

    return gpDec;
}

EXTERN_C int CDECL printf(const char *format,...)
{
    UInt32 BaseSp = (UInt32)&format;
    char *cp;
    UInt32 i = 1;
    char *p = NULL;

    char *pstr = (char *)format;
    while (*pstr != '\0') {
        if (*pstr != '%') {
            comPrintf(*pstr);
        }
        else if (*(pstr + 1) == 'x') {
            pstr++;
            cp = ToHexStr(*(int *)(BaseSp + i*4));
            i++;
            while (*cp != '\0') {
                comPrintf(*cp);
                cp++;
            }
        }
        else if (*(pstr + 1) == 'c') {
            pstr++;
            comPrintf(*(char *)(BaseSp + i*4));
            i++;
        }
        else if (*(pstr + 1) == 's') {
            pstr++;
            p = *(char **)(BaseSp + i*4);
            while (*p != '\0') {
                comPrintf(*p);
                p++;
            }
            i++;
        }
        else if (*(pstr + 1) == 'S') {
            pstr++;
            p = *(char **)(BaseSp + i*4);
            while (*p != '\0') {
                comPrintf(*p);
                p += 2;
            }
            i++;
        }
        else if (*(pstr + 1) == 'd') {
            pstr++;
            cp = ToDecStr(*(int *)(BaseSp + i*4));
            i++;
            while (*cp != '\0') {
                comPrintf(*cp);
                cp++;
            }
        }
        else if (*(pstr + 3) == 'x') {
            pstr += 3;
            cp = ToHexStr(*(int *)(BaseSp + i*4));
            i++;
            while (*cp != '\0') {
                comPrintf(*cp);
                cp++;
            }
        }
        else {
            __asm("break 0;");
        }

        pstr++;
    }

    return 0;
}
#endif
